package cn.xyfmzmy;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.locks.LockSupport;

/**
 * 自定义定时任务
 */
public class ScheduleService {

    // 线程池
    ExecutorService executorService = Executors.newFixedThreadPool(6);

    // 触发器
    Trigger trigger = new Trigger();

    // 添加定时任务方法
    void schedule(Runnable task, long delay) {
        Job job = new Job();
        job.setTask(task);
        job.setStartTime(System.currentTimeMillis() + delay);
        job.setDelay(delay);
        trigger.queue.offer(job);       // 将job放入优先队列中
        trigger.wakeUp();               // 唤醒线程
    }

    // 触发器，等待合适的时间，把对应的任务扔到线程池中
    class Trigger {

        // 要执行的任务集合(用阻塞优先队列)
        PriorityBlockingQueue<Job> queue = new PriorityBlockingQueue<>();

        Thread thread = new Thread(() -> {
            while(true){
                // 存在虚假唤醒问题,用if判断会导致空指针,需要用while
                while (queue.isEmpty()){
                    // JUC里的线程休眠api,无参就是一直等待，方便唤醒
                    LockSupport.park();
                }
                Job latelyJob = queue.peek();
                if(latelyJob.getStartTime() < System.currentTimeMillis()){
                    // 说明队列中有需要执行的任务,弹出来并执行
                    latelyJob = queue.poll();
                    executorService.execute(latelyJob.getTask());
                    // 计算下一次的执行时间，并重新放入优先级队列中
                    Job nextJob = new Job();
                    nextJob.setDelay(latelyJob.getDelay());
                    nextJob.setTask(latelyJob.getTask());
                    nextJob.setStartTime(System.currentTimeMillis() + latelyJob.getDelay());
                    queue.offer(nextJob);
                }else{
                    // 等待至latelyJob的执行时间
                    LockSupport.parkUntil(latelyJob.getStartTime());
                }
            }

            // 下面这段逻辑是错的，会导致线程被唤醒后仍执行原来的任务，而非新的优先级更高的任务
//                if(!queue.isEmpty()){
//                    // 获取最优先的任务
//                    Job job = queue.poll();
//                    long waitTime = job.getStartTime() - System.currentTimeMillis();
//                    // waitTime > 0 说明还没到执行时间
//                    if(waitTime > 0){
//
//                        LockSupport.park();
//                    }
//                    executorService.execute(job.getTask());
//                }
        });

        {
            thread.start();
            System.out.println("触发器启动了");
        }

        // 若一个任务等待1000ms,这时用户新添加一个任务，需要等待500ms
        // 这时仍需等待1000ms后才能执行新的任务,故需要唤醒机制,从1000ms的等待中唤醒，去执行新的任务
        void wakeUp(){
            // 唤醒线程
            LockSupport.unpark(thread);
        }

    }
}
